home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / dgsay.exe / DGSTR.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-06-29  |  22.2 KB  |  791 lines

  1. {
  2.  ╔═════════════════════════════════════════════════════════════════════════╗
  3.  ║                                                                         ║
  4.  ║        TITLE :      DGSTR.TPU,  Version 8907.01                         ║
  5.  ║      PURPOSE :      String Object and String Handling Routines          ║
  6.  ║       AUTHOR :      David Gerrold, CompuServe ID:  70307,544            ║
  7.  ║  _____________________________________________________________________  ║
  8.  ║                                                                         ║
  9.  ║   Written in Turbo Pascal, Version 5.5,                                 ║
  10.  ║   with routines from Turbo Professional, Version 5.0.                   ║
  11.  ║                                                                         ║
  12.  ║   Turbo Pascal is a product of Borland International.                   ║
  13.  ║   Turbo Professional is a product of TurboPower Software                ║
  14.  ║  _____________________________________________________________________  ║
  15.  ║                                                                         ║
  16.  ║  This is not public domain software.  This is shareware.                ║
  17.  ║  This software is copyright 1989, by David Gerrold.                     ║
  18.  ║                                                                         ║
  19.  ║        The Brass Cannon Corporation                                     ║
  20.  ║        9420 Reseda Blvd., #804                                          ║
  21.  ║        Northridge, CA 91324-2932.                                       ║
  22.  ║                                                                         ║
  23.  ║  If you find this code useful, a donation of $25 is requested --        ║
  24.  ║  not to me, but to the AIDS Project Los Angeles.  Donations may         ║
  25.  ║  be forwarded via the Brass Cannon address.  Thank you.                 ║
  26.  ║                                                                         ║
  27.  ╚═════════════════════════════════════════════════════════════════════════╝
  28.                                                                             }
  29. { ========================================================================= }
  30. {  Compiler Directives :                                                    }
  31. { ========================================================================= }
  32.  
  33. {$R-}    {Range checking off}
  34. {$B+}    {Boolean complete evaluation on}
  35. {$S+}    {Stack checking on}
  36. {$I+}    {I/O checking on}
  37. {$N+,E+} {Simulate numeric coprocessor}
  38. {$M 65500,16384,655360} {Turbo 3 default stack and heap}
  39. {$V-}    {Variable range checking off}
  40.  
  41. { ========================================================================= }
  42. UNIT DgStr;
  43. { ========================================================================= }
  44.  
  45. INTERFACE
  46.  
  47. USES
  48.   TpString,                                      { Turbo Power unit }
  49.   DgInit;                                        { Dg Initializations }
  50.  
  51. TYPE
  52.   StrOb = Object (LocOb)
  53.     S : string;
  54.  
  55.     Procedure  AcceptStr (NewStr : string);
  56.     Procedure  AcceptRaw (RawStr : string);
  57.     Procedure  UpStr;
  58.     Procedure  LoStr;
  59.     Procedure  UpCaseFirstLetter;
  60.     Procedure  TrimLeadCh  (Ch : char);
  61.     Procedure  TrimTrailCh (Ch : char);
  62.     Procedure  TrimCh      (Ch : char);
  63.     Procedure  StripOut    (Ch : char);
  64.     Procedure  OverWrite   (Position : byte;  OverStr : string);
  65.     Procedure  Replace     (OldStr, NewStr : string);
  66.     Procedure  Translate   (OldCh, NewCh : char);
  67.     Procedure  Append      (NewStr : string);
  68.     Procedure  AppendWord  (NewStr : string);
  69.     Procedure  HeadAppend  (NewStr : string);
  70.     Procedure  Compress;
  71.     Procedure  DeCompress;
  72.  
  73.     Function   L           : byte;
  74.     Function   LastPos     (PosCh : char) : byte;
  75.     Function   SubStr      (Pos1, Pos2 : byte) : string;
  76.     Function   ExtractFirstWord    : string;
  77.     Function   TrimThe             : string;
  78.   end;
  79.  
  80. { ========================================================================= }
  81.  
  82. FUNCTION TrimLeadChars (S : string;  Ch : char) : string;
  83. { Trims all occurrences of Ch from the beginning of a string. }
  84.  
  85. FUNCTION TrimTrailChars (S : string;  Ch : char) : string;
  86. { Trims all occurrences of Ch from the end of a string. }
  87.  
  88. FUNCTION TrimChars (S : string;  Ch : char) : string;
  89. { Trims all occurrences of Ch from the beginning and end of a string. }
  90.  
  91. FUNCTION InCap (Ch : char) : boolean;
  92. { Returns true if letter is upper case. }
  93.  
  94. FUNCTION Capitalize (S : string) : string;
  95. { Capitalizes the first letter in the string. }
  96.  
  97. FUNCTION CapitalizeAll (S : string) : string;
  98. { Capitalizes every word in the string. }
  99.  
  100. PROCEDURE ReplaceOnce (Var S : string;  OldStr, NewStr : string);
  101. { Finds OldStr in S and replaces it with NewStr. }
  102.  
  103. PROCEDURE ReplaceAll (Var S : string;  OldStr, NewStr : string);
  104. { Replaces all occurrences of OldStr with NewStr. }
  105.  
  106. FUNCTION GetSubStr (S : string; Pos1, Pos2 : byte) : string;
  107. { Extracts a SubString, starting at Pos1, ending at Pos2. }
  108.  
  109. FUNCTION Num2Str (Num : extended) : string;
  110. { Returns any number in shortest possible string. }
  111.  
  112. FUNCTION Str2Num (S : string) : real;
  113. { Turns a number in a string into a real number. }
  114.  
  115. FUNCTION InAlphabet (Ch : char) : boolean;
  116. { Returns true if ch in Alphabet. }
  117.  
  118. FUNCTION InNumbers (Ch : char) : boolean;
  119. { Returns true if ch is a number. }
  120.  
  121. FUNCTION InApostrophe (Ch : char) : boolean;
  122. { Returns true if ch is apostrophe. }
  123.  
  124. FUNCTION InTwoSpacePunctuation (Ch : char) : boolean;
  125. { Returns true if ch in two space punctuation. }
  126.  
  127. FUNCTION InPunctuation (Ch : char) : boolean;
  128. { Returns true if ch in punctuation. }
  129.  
  130. { ========================================================================= }
  131. { ========================================================================= }
  132.  
  133. IMPLEMENTATION
  134.  
  135. { ========================================================================= }
  136.  
  137. FUNCTION TrimLeadChars (S : string;  Ch : char) : string;
  138. {
  139.   Trims all occurrences of Ch from the beginning of S.
  140. }
  141.  
  142. VAR
  143.   Len  : byte absolute S;
  144.  
  145. BEGIN
  146.   While
  147.     (S [1] = Ch) and (Len > 0)                   { while S [1] = Ch }
  148.   do
  149.     begin
  150.     dec (Len);                                   { shorten S }
  151.     move (S [2], S [1], Len);                    { delete 1st char }
  152.     end;
  153.   TrimLeadChars := S;                            { return }
  154. END;
  155.  
  156. { ========================================================================= }
  157.  
  158. FUNCTION TrimTrailChars (S : string;  Ch : char) : string;
  159. {
  160.   Trims all occurrences of Ch from the end of S.
  161. }
  162.  
  163. VAR
  164.   Len  : byte absolute S;
  165.  
  166. BEGIN
  167.   While
  168.     (S [Len] = Ch)                               { while last char = Ch }
  169.   do
  170.     dec (Len);                                   { shorten S }
  171.   TrimTrailChars := S;                           { return }
  172. END;
  173.  
  174. { ========================================================================= }
  175.  
  176. FUNCTION TrimChars (S : string;  Ch : char) : string;
  177. {
  178.   Trims all occurrences of Ch from both the beginning and end of S.
  179. }
  180. BEGIN
  181.   TrimChars := TrimTrailChars (TrimLeadChars (S, Ch), Ch);
  182. END;
  183.  
  184. { ========================================================================= }
  185.  
  186. PROCEDURE StrOb.AcceptStr (NewStr : string);
  187. {
  188.   Accept a new string into S.
  189. }
  190. BEGIN
  191.   S := NewStr;
  192. END;
  193.  
  194. { ========================================================================= }
  195.  
  196. PROCEDURE StrOb.AcceptRaw (RawStr : String);
  197. {
  198.   Takes raw variable strings, such as those found in Turbo Pascal code,
  199.   and converts them to standard text strings.
  200.  
  201.   Will translate #39 into ' and ^E into Ctrl-E, etc.
  202.  
  203.   Useful for translating text strings from files.  No real
  204.   error-trapping here.  Routine tends to ignore what it doesn't
  205.   understand.  Nevertheless, use with caution.  Make sure input
  206.   strings are valid or results may be unpredictable.
  207. }
  208.  
  209. VAR
  210.   LenRawStr  : byte absolute RawStr;
  211.   Loop       : byte;
  212.   NumStr     : string [2];
  213.   Trash      : word;
  214.   Ch         : char;
  215.  
  216. BEGIN
  217. Loop := 1;
  218. S := '';
  219. While
  220.   Loop <= LenRawStr
  221. Do
  222.   Begin
  223.   Case RawStr [Loop] of
  224.     '^' : begin                             { Control Character }
  225.           inc (Loop);
  226.           Ch := Chr (Ord (UpCase (RawStr [Loop])) - 64);
  227.           If (Ch >= #0) and (Ch < #32) then S := S + Ch;
  228.           end;
  229.     '#' : begin                             { Decimal Character }
  230.           inc (Loop);
  231.           NumStr := '';
  232.           While
  233.             (RawStr [Loop] >= '0') and (RawStr [Loop] <= '9')
  234.               and (Loop <= LenRawStr)
  235.           do begin
  236.             NumStr := NumStr + RawStr [Loop];
  237.             Inc (Loop);
  238.             end;
  239.           dec (Loop);
  240.           If Str2Word (NumStr, Trash) then
  241.             S := S + Chr (Trash);
  242.           end;
  243.     #39 : begin                             { Text in single quotes }
  244.           inc (Loop);
  245.           While (RawStr [Loop] <> #39) and (Loop <= LenRawStr) do begin
  246.             S := S + RawStr [Loop];
  247.             inc (Loop);
  248.             end;
  249.           end;
  250.     end; { Case }
  251.   Inc (Loop);
  252.   end;
  253. END;
  254.  
  255. { ========================================================================= }
  256.  
  257. PROCEDURE StrOb.UpStr;
  258. {
  259.   Uppercases the string.
  260. }
  261. BEGIN
  262.   S := StUpCase (S);
  263. END;
  264.  
  265. { ========================================================================= }
  266.  
  267. PROCEDURE StrOb.LoStr;
  268. {
  269.   Lowercases the string.
  270. }
  271. BEGIN
  272.   S := StLoCase (S);
  273. END;
  274.  
  275. { ========================================================================= }
  276.  
  277. FUNCTION InCap (Ch : char) : boolean;            { 8906.01 }
  278. {
  279.   Returns true if Ch is upper case.
  280. }
  281. BEGIN
  282.   InCap := (Ch >= 'A') and (Ch <= 'Z');
  283. END;
  284.  
  285. { ========================================================================= }
  286.  
  287. FUNCTION Capitalize (S : string) : string;       { 8906.01 }
  288. {
  289.   Capitalizes the first letter in the string.
  290. }
  291. BEGIN
  292.   S := StLoCase (S);                             { lower case string }
  293.   S [1] := UpCase (S [1]);                       { upper case first letter }
  294.   Capitalize := S;                               { return }
  295. END;
  296.  
  297. { ========================================================================= }
  298.  
  299. FUNCTION CapitalizeAll (S : string) : string;    { 8906.01 }
  300. {
  301.   Capitalizes the first letter of every word in the string.
  302. }
  303.  
  304. VAR
  305.   Loop : byte;
  306.   Len  : byte absolute S;
  307.  
  308. BEGIN
  309.   S := StLoCase (S);                             { lower case string }
  310.   S [1] := UpCase (S [1]);                       { Cap first letter }
  311.   For Loop := 2 to Len do
  312.     If (S [Loop] <> ' ') and (S [pred (Loop)] = ' ') then
  313.       S [Loop] := UpCase (S [Loop]);
  314.   CapitalizeAll := S;
  315. END;
  316.  
  317. { ========================================================================= }
  318.  
  319. PROCEDURE StrOb.UpCaseFirstLetter;               { 8906.01 }
  320. {
  321.   Capitalizes the first letter in the string.
  322. }
  323. BEGIN
  324.   S := Capitalize (S);
  325. END;
  326.  
  327. { ========================================================================= }
  328.  
  329. PROCEDURE StrOb.TrimLeadCh (Ch : char);
  330. {
  331.   Removes all occurrences of Ch from the beginning of S.
  332. }
  333. BEGIN
  334.   S := TrimLeadChars (S, Ch);
  335. END;
  336.  
  337. { ========================================================================= }
  338.  
  339. PROCEDURE StrOb.TrimTrailCh (Ch : char);
  340. {
  341.   Removes all occurrences of Ch from the end of S.
  342. }
  343. BEGIN
  344.   S := TrimTrailChars (S, Ch);
  345. END;
  346.  
  347. { ========================================================================= }
  348.  
  349. PROCEDURE StrOb.TrimCh (Ch : char);
  350. {
  351.   Removes all occurrences of Ch from beginning and end of S.
  352. }
  353. BEGIN
  354.   S := TrimTrailChars (TrimLeadChars (S, Ch), Ch);
  355. END;
  356.  
  357. { ========================================================================= }
  358.  
  359. PROCEDURE StrOb.StripOut (Ch : char);
  360. {
  361.   Strips all occurrences of Ch from S, wheverever they occur.
  362. }
  363.  
  364. VAR
  365.   Len  : byte absolute S;
  366.   Loop : byte;
  367.  
  368. BEGIN
  369.   TrimCh (Ch);
  370.   For Loop := Len downto 1 do
  371.     If S [Loop] = Ch then begin
  372.       move (S [succ (Loop)], S [Loop], Len - Loop);
  373.       dec (Len);
  374.       end;
  375. END;
  376.  
  377. { ========================================================================= }
  378.  
  379. PROCEDURE StrOb.OverWrite (Position : byte;  OverStr : string);
  380. {
  381.   Replaces text in S at Position with text in OverStr.
  382.  
  383.   Although it would be faster to use 'move (OverStr, S, OverStrLen)',
  384.   that method does not correctly manage the length of S.  In specific,
  385.   using move does not allow S to concatenate extra chars if OverStr
  386.   goes beyond its length, nor will move manage the automatic truncation
  387.   of S if it grows beyond 255 chars.
  388. }
  389.  
  390. VAR
  391.   OverStrLen : byte absolute OverStr;
  392.  
  393. BEGIN
  394.   delete (S, Position, OverStrLen);              { delete current text }
  395.   insert (OverStr, S, Position);                 { insert new text }
  396. END;
  397.  
  398. { ========================================================================= }
  399.  
  400. PROCEDURE ReplaceOnce (Var S : string;  OldStr, NewStr : string);
  401. {
  402.   Finds first occurrence of OldStr, replaces it with NewStr.
  403. }
  404.  
  405. VAR
  406.   Position  : byte;
  407.   OldStrLen : byte absolute OldStr;
  408.  
  409. BEGIN
  410. Position := Pos (StUpCase (OldStr), StUpCase (S));   { find OldStr }
  411. If Position > 0 then begin                           { if OldStr exists }
  412.   delete (S, Position, OldStrLen);                   { delete it }
  413.   insert (NewStr, S, Position);                      { insert NewStr }
  414.   end;
  415. END;
  416.  
  417. { ========================================================================= }
  418.  
  419. PROCEDURE ReplaceAll (VAR S : string;
  420.                       OldStr, NewStr : string);
  421. {
  422.   Replaces all occurrences of OldStr with NewStr.
  423. }
  424.  
  425. BEGIN
  426. While Pos (OldStr, S) > 0 do
  427.   ReplaceOnce (S, OldStr, NewStr);
  428. END;
  429.  
  430. { ========================================================================= }
  431.  
  432. PROCEDURE StrOb.Replace (OldStr, NewStr : string);
  433. {
  434.   Finds first occurrence of OldStr, replaces it with NewStr.
  435. }
  436.  
  437. BEGIN
  438.   ReplaceOnce (S, OldStr, NewStr);
  439. END;
  440.  
  441. { ========================================================================= }
  442.  
  443. PROCEDURE StrOb.Translate (OldCh, NewCh : char);
  444. {
  445.   Finds every occurrence of OldCh, replaces it with NewCh.
  446. }
  447.  
  448. VAR
  449.   Len  : byte absolute S;
  450.   Loop : byte;
  451.  
  452. BEGIN
  453.   If OldCh <> NewCh then
  454.     For Loop := 1 to Len do
  455.       If S [Loop] = OldCh then
  456.         S [Loop] := NewCh;
  457. END;
  458.  
  459. { ========================================================================= }
  460.  
  461. PROCEDURE StrOb.Append (NewStr : string);
  462. {
  463.   Adds NewStr to end of S.
  464. }
  465.  
  466. BEGIN
  467.   S := S + NewStr;
  468. END;
  469.  
  470. { ========================================================================= }
  471.  
  472. PROCEDURE StrOb.AppendWord (NewStr : string);
  473. {
  474.   Adds ' ' and a word to the end of S.
  475. }
  476.  
  477. BEGIN
  478.   Append (' ' + NewStr);
  479. END;
  480.  
  481. { ========================================================================= }
  482.  
  483. PROCEDURE StrOb.HeadAppend (NewStr : string);
  484. {
  485.   Adds NewStr to the beginning of S.
  486. }
  487.  
  488. BEGIN
  489.   S := NewStr + S;
  490. END;
  491.  
  492. { ========================================================================= }
  493.  
  494. PROCEDURE StrOb.Compress;
  495. {
  496.   Takes S and compresses it at a ratio of 8:5.  Compression works by
  497.   converting 8-bit ASCII chararcters into 5-bit code.  Only letters
  498.   are unique.  Numbers and punctuation are ignored.  Based on routines
  499.   from Scott Bussinger.
  500. }
  501.  
  502. VAR
  503.   Len         : byte absolute S;
  504.   I           : word;
  505.   J           : word;
  506.   BitMask     : word;
  507.   ShiftFactor : word;
  508.   ResultStr   : string;
  509.  
  510. BEGIN
  511.   FillChar (ResultStr, sizeof(ResultStr), 0);    { Initialize result }
  512.   J := 1;
  513.   for I := 1 to Len do begin                     { Pack each char in turn }
  514.     ShiftFactor := (I + I + I) and 7;
  515.     case S[I] of
  516.       '0'..'9'  : BitMask := 27;
  517.       'a'..'z',
  518.       'A'..'Z'  : BitMask := ord (S[I]) and $1F;
  519.     else
  520.       BitMask := 0
  521.       end;  { case }
  522.     BitMask := BitMask shl ShiftFactor;
  523.     ResultStr [J] := chr (ord (ResultStr [J]) or lo (BitMask));
  524.     ResultStr [pred (J)] := chr (ord (ResultStr[pred (J)]) or hi (BitMask));
  525.     if ShiftFactor < 5 then
  526.       inc(J)
  527.     end;
  528.   ResultStr [0] := chr ((5 * Len + 7) shr 3);    { Set new length }
  529.   S := ResultStr
  530. END;
  531.  
  532. { ========================================================================= }
  533.  
  534. PROCEDURE StrOb.DeCompress;
  535. {
  536.   Takes compressed string S and decompresses it at a ratio of 5:8.
  537.   All letters are capitalized.  Numbers and punctuation are blanked.
  538.   May be some extra blanks on end.  Based on routines from
  539.   Scott Bussinger.
  540. }
  541.  
  542. TYPE
  543.   WordPtr = ^word;
  544.  
  545. VAR
  546.   Len         : byte absolute S;
  547.   I           : word;
  548.   J           : word;
  549.   ResultStr   : string;
  550.   ShiftFactor : word;
  551.  
  552. BEGIN
  553.   ResultStr [0] := chr ((8 * Len + 4) div 5);
  554.   FillChar (S [succ (Len)], 255 - Len, 0);
  555.            { In case we have a partially used last byte }
  556.   J := 0;
  557.   for I := 1 to length (ResultStr) do begin      { Get each char in turn }
  558.     ShiftFactor := (I + I + I) and 7;
  559.     ResultStr [I] := chr ((swap (WordPtr (@S[J])^) shr ShiftFactor)
  560.                           and $1F or $40);
  561.     case ResultStr [I] of
  562.       'A'..'Z': ;
  563.     else
  564.       ResultStr[I] := ' ';                       { Blank out odd chars }
  565.       end;
  566.     if ShiftFactor < 5 then
  567.       inc(J);
  568.     end;
  569.   S := ResultStr;
  570.   TrimTrailCh (' ');
  571. END;
  572.  
  573. { ========================================================================= }
  574.  
  575. FUNCTION StrOb.L : byte;
  576. {
  577.   Reports length of S, by returning value in Len.
  578. }
  579.  
  580. VAR
  581.   Len  : byte absolute S;
  582.  
  583. BEGIN
  584.   L := Len;
  585. END;
  586.  
  587. { ========================================================================= }
  588.  
  589. FUNCTION StrOb.LastPos (PosCh : char) : byte;
  590. {
  591.   Works like Pos function, but works from right to left.
  592. }
  593.  
  594. VAR
  595.   Loop : byte;
  596.   Len  : byte absolute S;
  597.  
  598. BEGIN
  599.   Loop := Len;
  600.   While
  601.     (S [Loop] <> PosCh)
  602.       and
  603.     (Loop > 0)
  604.   do
  605.     dec (Loop);
  606.   LastPos := Loop;
  607. END;
  608.  
  609. { ========================================================================= }
  610.  
  611. FUNCTION GetSubStr (S : string;  Pos1, Pos2 : byte) : string;
  612. {
  613.   Extracts a SubString, starting at Pos1, ending at Pos2.
  614. }
  615.  
  616. BEGIN
  617.   GetSubStr := Copy (S, Pos1, succ (Pos2) - Pos1);
  618. END;
  619.  
  620. { ========================================================================= }
  621.  
  622. FUNCTION StrOb.SubStr (Pos1, Pos2 : byte) : string;
  623. {
  624.   Extracts a SubString, starting at Pos1, ending at Pos2.
  625. }
  626.  
  627. BEGIN
  628.   SubStr := GetSubStr (S, Pos1, Pos2);
  629. END;
  630.  
  631. { ========================================================================= }
  632.  
  633. FUNCTION StrOb.ExtractFirstWord : string;        { 8906.01 }
  634. {
  635.   Extracts the first word from a string, and deletes it from the string.
  636. }
  637.  
  638. VAR
  639.   WordPos  : byte;
  640.   Len      : byte absolute S;
  641.  
  642. BEGIN
  643.   If Len > 0 then
  644.     begin
  645.     S := Trim (S);
  646.     WordPos := pos (' ', S);
  647.     ExtractFirstWord := SubStr (1, pred (WordPos));
  648.     S := SubStr (succ (WordPos), Len);
  649.     end
  650.   else
  651.     ExtractFirstWord := '';
  652. END;
  653.  
  654. { ======================================================================== }
  655.  
  656. FUNCTION StrOb.TrimThe : string;
  657. {
  658.   Removes 'A', 'An', and 'The' from the beginning of a string.
  659.  
  660.   CompUCString is a Turbo Professional function.
  661. }
  662.  
  663. BEGIN
  664.   If CompUCString ('A ', Copy (S, 1, 2)) = Equal then
  665.     delete (S, 1, 2)
  666.   else
  667.     If CompUCString ('AN ', Copy (S, 1, 3)) = Equal then
  668.       delete (S, 1, 3)
  669.     else
  670.       If CompUCString ('THE ', Copy (S, 1, 4)) = Equal then
  671.         delete (S, 1, 4);
  672.   TrimThe := S;
  673. END;
  674.  
  675. { ========================================================================= }
  676.  
  677. FUNCTION  Num2Str (Num : extended) : string;
  678. {
  679.   Num2Str takes any number and returns it as the shortest possible string.
  680. }
  681.  
  682. VAR
  683.   S        : string;
  684.   Len      : byte absolute S;
  685.   ExpStr   : string [4];
  686.   EPos,
  687.   E        : word;
  688.  
  689.   FUNCTION TrimStr (S : string) : string;
  690.   {
  691.     Trims spaces, trims '0's, then trims trailing decimal point.
  692.     If first char in S is a decimal point, restores leading 0.
  693.     If S is reduced to '', function returns 0.
  694.   }
  695.   BEGIN
  696.   S := TrimTrailChars (TrimChars (TrimChars (S, ' '), '0'), '.');
  697.   If S [1] = '.' then insert ('0', S, 1);
  698.   If S > '' then TrimStr := S else TrimStr := '0';
  699.   END;
  700.  
  701. BEGIN
  702.   Str (Num, S);                         { convert to str + E }
  703.   EPos   := Pos ('E', S);               { where is 'E' ? }
  704.   ExpStr := GetSubStr (S, EPos + 2, Len);
  705.   If not Str2Word (ExpStr, E) then      { E := abs value of exponent }
  706.     Num2Str := ''
  707.   else
  708.     If E > 10 then
  709.       Num2Str := TrimStr (GetSubStr (S, 1, Pred (Epos))) +
  710.                  GetSubStr (S, EPos, Succ (EPos)) +       { E + or - }
  711.                  TrimLeadChars (GetSubStr (S, EPos + 2, Len), '0')
  712.     else
  713.       Num2Str := TrimStr (Real2Str (Num, 35, 18));
  714. END;
  715.  
  716. { ========================================================================= }
  717.  
  718. FUNCTION  Str2Num (S : string) : real;
  719. {
  720.   Turns a string into a real.
  721. }
  722.  
  723. VAR
  724.   R : float;
  725.  
  726. BEGIN
  727.   If Str2Real (S, R) then
  728.     Str2Num := R
  729.   else
  730.     Str2Num := 0;
  731. END;
  732.  
  733. { ========================================================================= }
  734.  
  735. {$B-}
  736. FUNCTION InAlphabet (Ch : char) : boolean;
  737. { Returns true if ch in Alphabet. }
  738.  
  739. BEGIN
  740.   InAlphabet := ((Ch > #96) and (Ch < #123))
  741.                   or
  742.                 ((Ch > #64) and (Ch < #91));
  743. END;
  744. {$B+}
  745.  
  746. { ========================================================================= }
  747.  
  748. FUNCTION InNumbers (Ch : char) : boolean;
  749. { Returns true if ch is a number. }
  750.  
  751. BEGIN
  752.   InNumbers := (Ch > #47) and (Ch < #58);
  753. END;
  754.  
  755. { ========================================================================= }
  756.  
  757. FUNCTION InApostrophe (Ch : char) : boolean;
  758. { Returns true if ch is apostrophe. }
  759.  
  760. BEGIN
  761.   InApostrophe := (Ch = #39);
  762. END;
  763.  
  764. { ========================================================================= }
  765.  
  766. FUNCTION InTwoSpacePunctuation (Ch : char) : boolean;
  767. { Returns true if ch in two space punctuation. }
  768.  
  769. BEGIN
  770.   InTwoSpacePunctuation := Pos (Ch, '.!?;:') > 0;
  771. END;
  772.  
  773. { ========================================================================= }
  774.  
  775. FUNCTION InPunctuation (Ch : char) : boolean;
  776. { Returns true if ch in punctuation. }
  777.  
  778. BEGIN
  779.   InPunctuation := not InAlphabet (Ch) and
  780.                    not InNumbers (Ch) and
  781.                    not InApostrophe (Ch);
  782. END;
  783.  
  784. { ========================================================================= }
  785. { Initialization }
  786. { ========================================================================= }
  787.  
  788. END.
  789.  
  790. { ========================================================================= }
  791.